import requests
import json
import sys
import os
from datetime import datetime

def load_config(config_file='config.json'):
    """Load configuration from JSON file"""
    try:
        with open(config_file, 'r', encoding='utf-8') as f:
            return json.load(f)
    except FileNotFoundError:
        print(f"Configuration file {config_file} not found!")
        sys.exit(1)
    except json.JSONDecodeError:
        print(f"Invalid JSON in configuration file {config_file}!")
        sys.exit(1)

def get_environment_config(config, env_name):
    """Get configuration for specified environment"""
    if env_name not in config:
        print(f"Environment '{env_name}' not found in configuration!")
        print(f"Available environments: {list(config.keys())}")
        sys.exit(1)
    return config[env_name]

class GitLabCommitHistory:
    def __init__(self, base_url, token):
        self.base_url = base_url
        self.headers = {'PRIVATE-TOKEN': token}
        self.session = requests.Session()
        self.session.headers.update(self.headers)
    
    def get_projects(self, limit=10):
        """Get a list of projects"""
        projects_url = f'{self.base_url}/projects?per_page={limit}'
        
        try:
            response = self.session.get(projects_url, timeout=10)
            if response.status_code == 200:
                return response.json()
            else:
                print(f"Failed to get projects: {response.status_code}")
                print(response.text)
                return []
        except Exception as e:
            print(f"Error getting projects: {e}")
            return []
    
    def get_project_by_name(self, project_name):
        """Find a project by name"""
        projects_url = f'{self.base_url}/projects?search={project_name}'
        
        try:
            response = self.session.get(projects_url, timeout=10)
            if response.status_code == 200:
                projects = response.json()
                for project in projects:
                    if project['name'].lower() == project_name.lower():
                        return project
                return None
            else:
                print(f"Failed to search projects: {response.status_code}")
                return None
        except Exception as e:
            print(f"Error searching projects: {e}")
            return None
    
    def get_commit_history(self, project_id, author_email=None, author_name=None, limit=20, since=None, until=None):
        """Get commit history for a project, optionally filtered by author"""
        commits_url = f'{self.base_url}/projects/{project_id}/repository/commits'
        
        params = {
            'per_page': limit,
            'page': 1
        }
        
        if author_email:
            params['author'] = author_email
        if since:
            params['since'] = since
        if until:
            params['until'] = until
        
        try:
            response = self.session.get(commits_url, params=params, timeout=10)
            if response.status_code == 200:
                commits = response.json()
                
                # If author_name is specified but not email, filter by name
                if author_name and not author_email:
                    filtered_commits = []
                    for commit in commits:
                        if (commit.get('author_name', '').lower() == author_name.lower() or 
                            commit.get('committer_name', '').lower() == author_name.lower()):
                            filtered_commits.append(commit)
                    return filtered_commits
                
                return commits
            else:
                print(f"Failed to get commits: {response.status_code}")
                print(response.text)
                return []
        except Exception as e:
            print(f"Error getting commits: {e}")
            return []
    
    def display_commits(self, commits, detailed=False):
        """Display commit information"""
        if not commits:
            print("No commits found.")
            return
        
        print(f"\nFound {len(commits)} commits:")
        print("=" * 80)
        
        for i, commit in enumerate(commits, 1):
            commit_id = commit.get('id', 'N/A')[:8]
            title = commit.get('title', 'N/A')
            author_name = commit.get('author_name', 'N/A')
            author_email = commit.get('author_email', 'N/A')
            created_at = commit.get('created_at', 'N/A')
            
            # Parse and format date
            try:
                if created_at != 'N/A':
                    dt = datetime.fromisoformat(created_at.replace('Z', '+00:00'))
                    formatted_date = dt.strftime('%Y-%m-%d %H:%M:%S')
                else:
                    formatted_date = 'N/A'
            except:
                formatted_date = created_at
            
            if detailed:
                print(f"\n{i}. Commit Details:")
                print(f"   ID: {commit.get('id', 'N/A')}")
                print(f"   Title: {title}")
                print(f"   Message: {commit.get('message', 'N/A')}")
                print(f"   Author: {author_name} <{author_email}>")
                print(f"   Date: {formatted_date}")
                print(f"   Web URL: {commit.get('web_url', 'N/A')}")
                if commit.get('stats'):
                    stats = commit['stats']
                    print(f"   Changes: +{stats.get('additions', 0)} -{stats.get('deletions', 0)} (total: {stats.get('total', 0)})")
                print("-" * 60)
            else:
                print(f"{i:2d}. {commit_id} | {formatted_date} | {author_name[:20]:20} | {title[:40]}")
    
    def save_commits_to_file(self, commits, filename, project_info=None):
        """Save commits to JSON file"""
        output_data = {
            'export_time': datetime.now().isoformat(),
            'project_info': project_info,
            'total_commits': len(commits),
            'commits': commits
        }
        
        try:
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(output_data, f, indent=2, ensure_ascii=False)
            print(f"\nCommits saved to: {filename}")
        except Exception as e:
            print(f"Failed to save commits: {e}")

def main():
    # Get script directory to find config file
    script_dir = os.path.dirname(os.path.abspath(__file__))
    config_file = os.path.join(script_dir, 'config.json')
    
    # Load configuration
    config = load_config(config_file)
    
    # Parse command line arguments
    if len(sys.argv) < 2:
        print("Usage: python get_commit_history.py <environment> [options]")
        print(f"Available environments: {list(config.keys())}")
        print("\nOptions:")
        print("  --project <name>       Specify project name")
        print("  --project-id <id>      Specify project ID")
        print("  --author-email <email> Filter by author email")
        print("  --author-name <name>   Filter by author name")
        print("  --limit <number>       Number of commits to retrieve (default: 20)")
        print("  --detailed             Show detailed commit information")
        print("  --save                 Save results to JSON file")
        print("  --list-projects        List available projects")
        print("\nExamples:")
        print("  python get_commit_history.py local --list-projects")
        print("  python get_commit_history.py local --project founder_module --limit 10")
        print("  python get_commit_history.py local --project-id 570 --author-name 'John Doe' --detailed")
        sys.exit(1)
    
    env_name = sys.argv[1]
    
    # Parse options
    project_name = None
    project_id = None
    author_email = None
    author_name = None
    limit = 20
    detailed = '--detailed' in sys.argv
    save_to_file = '--save' in sys.argv
    list_projects = '--list-projects' in sys.argv
    
    # Parse parameter values
    args = sys.argv[2:]
    i = 0
    while i < len(args):
        if args[i] == '--project' and i + 1 < len(args):
            project_name = args[i + 1]
            i += 2
        elif args[i] == '--project-id' and i + 1 < len(args):
            project_id = int(args[i + 1])
            i += 2
        elif args[i] == '--author-email' and i + 1 < len(args):
            author_email = args[i + 1]
            i += 2
        elif args[i] == '--author-name' and i + 1 < len(args):
            author_name = args[i + 1]
            i += 2
        elif args[i] == '--limit' and i + 1 < len(args):
            limit = int(args[i + 1])
            i += 2
        else:
            i += 1
    
    # Get environment configuration
    env_config = get_environment_config(config, env_name)
    base_url = env_config['url']
    token = env_config['token']
    
    print(f"GitLab Commit History Analyzer")
    print(f"Environment: {env_name}")
    print(f"API URL: {base_url}")
    print()
    
    try:
        # Initialize GitLab commit history analyzer
        history_analyzer = GitLabCommitHistory(base_url, token)
        
        # List projects if requested
        if list_projects:
            print("Available projects (showing first 20):")
            projects = history_analyzer.get_projects(20)
            for project in projects:
                print(f"  ID: {project['id']:3d} | Name: {project['name']} | Path: {project['path_with_namespace']}")
            return
        
        # Get project information
        project_info = None
        if project_name:
            project_info = history_analyzer.get_project_by_name(project_name)
            if not project_info:
                print(f"Project '{project_name}' not found!")
                sys.exit(1)
            project_id = project_info['id']
        elif project_id:
            # Get project info by ID
            try:
                response = history_analyzer.session.get(f"{base_url}/projects/{project_id}", timeout=10)
                if response.status_code == 200:
                    project_info = response.json()
                else:
                    print(f"Project with ID {project_id} not found!")
                    sys.exit(1)
            except Exception as e:
                print(f"Error getting project info: {e}")
                sys.exit(1)
        else:
            print("Please specify either --project <name> or --project-id <id>")
            print("Use --list-projects to see available projects")
            sys.exit(1)
        
        print(f"Project: {project_info['name']} (ID: {project_info['id']})")
        print(f"Description: {project_info.get('description', 'N/A')}")
        print(f"Web URL: {project_info.get('web_url', 'N/A')}")
        
        filter_info = []
        if author_email:
            filter_info.append(f"author email: {author_email}")
        if author_name:
            filter_info.append(f"author name: {author_name}")
        if filter_info:
            print(f"Filters: {', '.join(filter_info)}")
        print(f"Limit: {limit} commits")
        print()
        
        # Get commit history
        commits = history_analyzer.get_commit_history(
            project_id, 
            author_email=author_email, 
            author_name=author_name, 
            limit=limit
        )
        
        # Display results
        history_analyzer.display_commits(commits, detailed)
        
        # Save to file if requested
        if save_to_file:
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            filename = f"commits_{project_info['name']}_{timestamp}.json"
            history_analyzer.save_commits_to_file(commits, filename, project_info)
        
    except KeyboardInterrupt:
        print("\nOperation cancelled by user.")
        sys.exit(1)
    except Exception as e:
        print(f"Error occurred: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()
